package com.example.first.thread;

import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author LSQ
 * @Description 实践证明ThreadLocal是线程安全的
 * @date 2021/8/6 16:42
 * @Version 1.0
 */

class Person {
    private ThreadLocal<String> name = new ThreadLocal<>();

    public String getName() {
        return this.name.get();
    }

    public void setName(String name) {
        this.name.set(name);
    }

    public void remove(){
        this.name.remove();
    }
}

public class LearnThreadLocal1 {

    private static final int ARRAY_BLOCKING_QUEUE_CAPACITY = 1000;
    private static final int COOL_POOL_SIZE = 100;
    private static final int MAXIMUM_POOL_SIZE = 100;
    private static final int KEEP_ALIVE_TIME = 60;
    private static final int TASK_NUMBER = 500;

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(COOL_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(ARRAY_BLOCKING_QUEUE_CAPACITY));
        Person person = new Person();
        for (int i = 0; i < TASK_NUMBER; i++) {
            String myName = "lsq" + i;
            Runnable runnable = () -> {
                person.setName(myName);
                System.out.printf("Task [ %s ] print person name: %s  person object address is: %s \n", Thread.currentThread().getName(), person.getName(), System.identityHashCode(person));
                person.remove(); // 移除ThreadLocalMap里面的缓存的内容
            };
            executorService.submit(runnable);

        }


    }
}


/*
ThreadLocal 的目的是让每个线程都生成一个实例的副本

源代码：

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

1、Thread对象内部有个ThreadLocalMap，这个map的k就是threadlocal对象，v就是传进去的值（缓存）
所以在线程1中set的值，对线程2来说是摸不到的，而且在线程2中重新set的话，也不会影响到线程1中的值，保证了线程之间不会相互干扰。

Thread对象 --- ThreadLocalMap [ threadlocal对象, 传进去的值  ]

2、垃圾回收问题
Thread对象如果不存在了，ThreadLocalMap要释放；
如果是用线程池创建的线程，核心线程会一直存在，ThreadLocalMap也就会一直存在，就会侵蚀JVM的内存，造成内存泄漏

3、手工remove

调用ThreadLocal的remove方法可以清理缓存中的数据



 */